package pt.inescid.components.policyengine.heimdall.contact;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

import pt.inescid.components.policyengine.heimdall.commons.Log;
import pt.inescid.components.policyengine.heimdall.commons.ProjectInfo;

public class OutboundThread extends Thread {
	
	private RemoteCommand command = null;

    private Socket socket = null;
    private ObjectOutputStream objectOut = null;
    private ObjectInputStream objectIn = null;
	
    private RemoteResponse response = null;
    

	/* ===========================================================
	==============================================================
	=============                    =============================
	=============      constructor       =============================
	=============                    =============================
	==============================================================
	=========================================================== */
    public OutboundThread(RemoteCommand command) {
    	super("OutboundThread");
    	
    	this.command = command;
 
		Log.debug(Log.INFO, "Arrived", "OutboundThread.constructor");

    } // constructor
    
    
    
    
    
    
	/* ===========================================================
	==============================================================
	=============                    =============================
	=============      run       =============================
	=============                    =============================
	==============================================================
	=========================================================== */
    public void run() {
    	
		Log.debug(Log.INFO, "Arrived.", "OutboundThread.run");

		// Open a socket to the destination node and send the command
		try {
			if (ProjectInfo.isEnabled(ProjectInfo.REMOTE_FEATURE)) {
				socket = new Socket(command.getHostname(), 
						command.getHostport());
				objectOut = new ObjectOutputStream(socket.getOutputStream());
				objectIn = new ObjectInputStream(socket.getInputStream());
			}
			
			// process the request
			dispatch(command);
			
//			switch (command.getType()) {
//			case RemoteCommand.LOAD_CES_COMMAND:
//				exportCes(command);
//				break;
//			case RemoteCommand.QUERY_CES_COMMAND:
//				queryCes(command);
//				break;
//			case RemoteCommand.REMOTE_EVALUATION_COMMAND:
//				remoteEvaluation(command);
//				break;
//			case RemoteCommand.TEST_COMMAND:
//				testSystem(command);
//				break;
//			case RemoteCommand.RESPONSE_COMMAND:
//				testSystem(command);
//				break;
//				
//			default:
//				break;
//			}
			
			Log.debug(Log.INFO, "Disconnecting.", "OutboundThread.run");
			
			if (ProjectInfo.isEnabled(ProjectInfo.REMOTE_FEATURE)) {
				
				// close all communication
				objectOut.close();
				objectIn.close();
				socket.close();
			}
		} catch (UnknownHostException e) {
			Log.debug(Log.ERROR, "Don't know about " + 
					command.getHostname() + 
					":" + 
					command.getHostport() + 
					" - " + e.getMessage(), "OutboundThread.run");
			
			System.err.println("Don't know about " + 
					command.getHostname() + 
					":" + 
					command.getHostport() + 
					" - " + e.getMessage());
			System.exit(1);
		} catch (IOException e) {
			Log.debug(Log.ERROR, "Couldn't get I/O for the connection to " + 
					command.getHostname() + 
					":" + 
					command.getHostport() + 
					" - " + e.getMessage(), 
			"OutboundThread.run");
			
			System.err.println("Couldn't get I/O for the connection to " + 
					command.getHostname() + 
					":" + 
					command.getHostport() + 
					" - " + e.getMessage());
			System.exit(1);
		} catch (Exception e) {
			Log.debug(Log.ERROR, "Outro erro em " + 
					command.getHostname() + 
					":" + 
					command.getHostport() + 
					" - " + e.getMessage(), 
			"OutboundThread.run");
		}
		
		Log.debug(Log.INFO, "Finished.", "OutboundThread.run");
   } // run
    
     
    
    
	/* ===========================================================
	==============================================================
	=============                    =============================
	=============      dispatch       =============================
	=============                    =============================
	==============================================================
	=========================================================== */
	public void dispatch(RemoteCommand command) throws Exception {
		
		Log.debug(Log.INFO, "Arrived", "OutboundThread.dispatch");

		if (ProjectInfo.isEnabled(ProjectInfo.REMOTE_FEATURE)) {
		
			// send the command
			objectOut.writeObject(command);
			
			Log.debug(Log.INFO, "Sent command.", "OutboundThread.dispatch");
			
			// wait for the confirmal receipt
			response = (RemoteResponse) objectIn.readObject();
			
			Log.debug(Log.INFO, "Received response: " +
					response, "OutboundThread.queryCes");
			
		
			if (response == null ||
					response.getType() != RemoteResponse.OK_RESPONSE) {
			
			// TODO
			}
		}
		else {
			InboundThread.registerCommand(command);
		}
	} // dispatch  

   
    
    
	/* ===========================================================
	==============================================================
	=============                    =============================
	=============      exportCes       =============================
	=============                    =============================
	==============================================================
	=========================================================== */
	public void exportCes(RemoteCommand command) throws Exception {

		Log.debug(Log.INFO, "Arrived", "OutboundThread.exportCes");

		// send the command
		objectOut.writeObject(command);
		
		Log.debug(Log.INFO, "Sent command.", "OutboundThread.exportCes");
		
		response = (RemoteResponse) objectIn.readObject();
		
		Log.debug(Log.INFO, "Received response: " +
				response, "OutboundThread.exportCes");
			
	} // exportCes
	
	
	
	
	/* ===========================================================
	==============================================================
	=============                    =============================
	=============      queryCes       =============================
	=============                    =============================
	==============================================================
	=========================================================== */
	public void queryCes(RemoteCommand command) throws Exception {
		
		Log.debug(Log.INFO, "Arrived", "OutboundThread.queryCes");

		if (ProjectInfo.isEnabled(ProjectInfo.REMOTE_FEATURE)) {
		
			// send the command
			objectOut.writeObject(command);
			
			Log.debug(Log.INFO, "Sent command.", "OutboundThread.queryCes");
			
			// wait for the confirmal receipt
			response = (RemoteResponse) objectIn.readObject();
			
			Log.debug(Log.INFO, "Received response: " +
					response, "OutboundThread.queryCes");
			
		
			if (response == null ||
					response.getType() != RemoteResponse.OK_RESPONSE) {
			}
		}
		else {
			InboundThread.registerCommand(command);
		}
	} // queryCes  
	
	
	
	
	
	/* ===========================================================
	==============================================================
	=============                    =============================
	=============      remoteEvaluation       =============================
	=============                    =============================
	==============================================================
	=========================================================== */
	public void remoteEvaluation(RemoteCommand command) throws Exception {
		
		Log.debug(Log.INFO, "Arrived", "OutboundThread.remoteEvaluation");

		if (ProjectInfo.isEnabled(ProjectInfo.REMOTE_FEATURE)) {
		
			// send the command
			objectOut.writeObject(command);
			
			Log.debug(Log.INFO, "Sent command.", "OutboundThread.queryCes");
			
			// wait for the confirmal receipt
			response = (RemoteResponse) objectIn.readObject();
			
			Log.debug(Log.INFO, "Received response: " +
					response, "OutboundThread.queryCes");
			
			if (response == null ||
					response.getType() != RemoteResponse.OK_RESPONSE) {
			}
		}
	} // remoteEvaluation  
	
	
	
	
	
	/* ===========================================================
	==============================================================
	=============                    =============================
	=============      testSystem       =============================
	=============                    =============================
	==============================================================
	=========================================================== */
	public void testSystem(RemoteCommand command) throws Exception {
		
		if (ProjectInfo.isEnabled(ProjectInfo.REMOTE_FEATURE)) {
			
			// send the command
			objectOut.writeObject(command);

			// wait for the confirmal receipt
			response = (RemoteResponse) objectIn.readObject();
			
			if (response == null ||
					response.getType() != RemoteResponse.OK_RESPONSE) {
			}
		}
	} // testSystem  


}; // OutboundThread
